#include "vg.h"
#include "utypes.h"

int HRES,VRES;

unsigned long get_address(int mode){
	__dpmi_regs regs;
	unsigned long dosbuf, address = 0;
	
	dosbuf = __tb & 0xFFFFF;
	dosmemput(&address, 4, dosbuf + 40);
	
	regs.x.ax = 0x4F01;
	regs.x.di = dosbuf & 0xF;
	regs.x.es = (dosbuf >> 4) & 0xFFFF;
	regs.x.cx = mode;
	
	__dpmi_int(0x10, &regs);
	if(regs.h.ah){
		return 0;
	}
	dosmemget(dosbuf + 40 , 4, &address);
	if(!address){
		return 0;
	}
	return address;
}

char * enter_graphics(int mode, __dpmi_meminfo *map){
	 __dpmi_regs regs;
	 char* video_mem;
	 
	 
	 regs.x.ax = 0x4F02;
	 regs.x.bx = 0x4000 + mode;
	 
	 __dpmi_int(0x10, &regs);
	 __djgpp_nearptr_enable();
	 
	 map->address = get_address(mode);
	 
	 if(mode == 0x101){
		HRES=640;
		VRES=480;
	 }
	 else if(mode == 0x103){
	 	HRES=800;
		VRES=600;
	 }
	 else if(mode == 0x105){
	 	HRES=1024;
		VRES=768;
	 }
	 else if(mode == 0x107){
	 	HRES=1280;
		VRES=1024;
	 }
	 
	 map->size = HRES * VRES;
	 __dpmi_physical_address_mapping(map);
	 video_mem = (char*) (map->address + __djgpp_conventional_base);
	 
	 return video_mem;
}

void leave_graphics(__dpmi_meminfo map){
	__dpmi_regs regs;

	__dpmi_free_physical_address_mapping(&map);
	__djgpp_nearptr_disable();
	
	regs.x.ax = 0x0003;
	__dpmi_int(0x10,&regs);
}

void set_pixel(int x, int y, int color, char *base){
	//if(x<0 || x > HRES || y < 0 || y> VRES)
		//return;
	
	*(base + y*HRES + x) = color;
}

int get_pixel(int x, int y, char *base){
	if(x<0 || x > HRES || y < 0 || y> VRES)
		return -1;
		
	return (int) *(base + y*HRES + x);
}

void clear_screen(char color, char *base){
	int x,y;
	for(y=0;y<VRES;++y){
		for(x=0;x<HRES;++x){
			set_pixel(x,y,color,base);
		}
	}
}




void draw_line(int xi, int yi, int xf, int yf, int color, char *base){
	int temp = 0, deltax = xf - xi, deltay = abs(yf - yi), ystep = 0, y = yi, x = xi;
	float error = 0.0, deltaerr = (float) deltay / deltax;
		
	Bool steep = abs(yf - yi) > abs(xf - xi);

	if(steep){
		temp = xi;
		xi = yi;
		yi = temp;
		temp = xf;
		xf = yf;
		yf = temp;
	}
	
	if(xi > xf){
		temp = xi;
		xi = xf;
		xf = temp;
		temp = yi;
		yi = yf;
		yf = temp;
	}
	
	ystep = (yi < yf) ? 1 : -1;
	
	for( ; x < xf; x++){
		if(steep){
			set_pixel(y, x, color, base);
		}
		else{
			set_pixel(x, y, color, base);
		}
		error += deltaerr;
		if(error >= 0.5){
			y += ystep;
			error -= 1.0;
		}
	}				 
}

void drawCharAt(char c, int x, int y, int fore_color, int back_color,
				int char_scale, char* video_base, char* table)
{
	// posição do carácter c em table (lida de po.dat)
	char* char_def = table + c * CHR_H;

	int i, j;
	Byte mask = 0x80;
	int color;
	int x_act, y_act, sx, sy;
	// usar operadores bitwise para isolar e testar cada um dos bits
	for (j = 0, y_act = y; j < CHR_H; j++, y_act += char_scale) // for each character row
	{
		for (i = 0, x_act = x; i < 8; i++, x_act += char_scale)		// for each pixel in row
		{
			color = (*char_def & (mask >> i)) ? fore_color : back_color;
			for(sx = 0; sx < char_scale; sx++)
					for(sy = 0; sy < char_scale; sy++)
						if(color != back_color)
							set_pixel(x_act + sx, y_act + sy, color, video_base);
		}
		char_def++;
	}
}	


void drawStringAt(char* str, int x, int y, int fore_color, int back_color,
				int char_scale, char *video_base, char *table)
{
	int i = 0;
	while(str[i] != 0)
	{
		drawCharAt(str[i], x + 8 * char_scale * i, y, fore_color, back_color, char_scale, video_base, table);
		i++;
	}
}
		
		
void drawIntAt(int num, int x, int y, int fore_color, int back_color,
				int char_scale, char *video_base, char *table)
{
	int i = 0;
	
	//se o numero for negativo, imprimir '-'
	if(num < 0)
	{
		drawCharAt('-', x, y, fore_color, back_color, char_scale, video_base, table);
		i++;
		num = 0 - num;
	}
	
	//descobrir a ordem de grandeza do numero
	int ordem = 1;
	while(num / ordem >= 10) ordem *= 10;
	
	//da esquerda para a direita, imprimir os algarismos
	while(true)
	{
		int digito = num / ordem;
		drawCharAt(digito + '0', x + 8 * char_scale * i, y, fore_color, back_color, char_scale, video_base, table);
		num -= digito * ordem;
		if(ordem == 1) break;
		ordem /= 10;
		i++;
	}
}



